﻿using MaterialTypeRecognition.Shell.AuthenticationServices;
using MaterialTypeRecognition.Shell.Logs;
using MaterialTypeRecognition.Shell.ViewModels;
using MaterialTypeRecognition.Shell.Views;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Windows;

namespace MaterialTypeRecognition.Shell
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private IHost? _host;

        public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
              .ConfigureWebHostDefaults(webBuilder =>
              {
                  webBuilder.UseStartup<WebStartup>();  // 配置 ASP.NET Core Web API的Startup类
              })
              .ConfigureAppConfiguration((hostContext, config) =>
              {
                  var appAssembly = Assembly.Load(new AssemblyName(hostContext.HostingEnvironment.ApplicationName));
                  var appPath = Path.GetDirectoryName(appAssembly.Location) ?? AppContext.BaseDirectory;
                  config.SetBasePath(appPath);
                  config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
              })
              .ConfigureServices((hostContext, services) =>
              {
                  services.AddLogging(logBuilder =>
                  {
                      var appAssembly = Assembly.Load(new AssemblyName(hostContext.HostingEnvironment.ApplicationName));
                      var appPath = Path.GetDirectoryName(appAssembly.Location) ?? AppContext.BaseDirectory;
                      appPath = Path.Combine(appPath, "ConfigurationFiles");
                      logBuilder.ClearProviders();
                      logBuilder.SetMinimumLevel(LogLevel.Trace);
                      logBuilder.AddLog4Net(Path.Combine(appPath, "log4net.config")); // 使用appPath路径来指定log4net配置文件的位置
                  });

                  // 注册日志记录器工厂
                  services.AddSingleton<MaterialTypeRecognition.Shell.Logs.ILog4NetLoggerFactory, MaterialTypeRecognition.Shell.Logs.Log4NetLoggerFactory>();

                  AppServiceRegistry.OnRegisterServices(services);
              });

        protected async override void OnStartup(StartupEventArgs e)
        {
            if (AlreadyRun())
            {
                MessageBox.Show("软件已运行！", "提示");
                this.Shutdown();
                return;
            }

            var baseDir = Path.GetDirectoryName(typeof(App).Assembly.Location);

            if (string.IsNullOrWhiteSpace(baseDir))
            {
                MessageBox.Show("应用程序基目录为空！");
                this.Shutdown();
                return;
            }

            LoadCert(baseDir);

            _host = CreateHostBuilder(Environment.GetCommandLineArgs()).Build();

            var applog = _host.Services.GetRequiredService<ILog4NetLoggerFactory>().GetAppLogger();
            try
            {
                this.MainWindow = _host.Services.GetRequiredService<MainWindow>();
                this.MainWindow.Closing += MainWindow_Closing;
                this.MainWindow.DataContext = _host.Services.GetRequiredService<MainWindowViewModel>();
                this.MainWindow.Show();

                var tipWindow = _host.Services.GetRequiredService<TopTipWindow>();
                var viewModel = _host.Services.GetRequiredService<TopTipWindowViewModel>();
                viewModel.OwnerWindow = tipWindow;
                tipWindow.DataContext = viewModel;
                tipWindow.Show();

                // 启动 web 主机。
                await _host.StartAsync();
            }
            catch (Exception ex)
            {
                applog.Error(ex);
            }
            _host.Services.GetRequiredService<ILog4NetLoggerFactory>().GetOperationLogger()
                .Info("应用程序启动");
        }

        private void MainWindow_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
        {
            if (_host != null)
            {
                var applog = _host.Services.GetRequiredService<ILog4NetLoggerFactory>().GetAppLogger();
                var service = _host.Services.GetRequiredService<IAuthenticationService>();

                try
                {
                    if (!service.OPNAuthenticate())
                    {
                        e.Cancel = true;
                        MessageBox.Show("您没有权限关闭软件！");
                    }
                    else
                    {
                        _host.Services.GetRequiredService<TopTipWindow>().Close();
                    }
                }
                catch (Exception ex)
                {
                    applog.Error(ex);
                }
            }
        }

        protected async override void OnExit(ExitEventArgs e)
        {
            base.OnExit(e);

            if (_host != null)
            {
                await _host.StopAsync();
                _host.Services.GetRequiredService<ILog4NetLoggerFactory>().GetOperationLogger()
                   .Info("应用程序关闭");
            }
        }

        private static Mutex? InstanceMutex = null;

        private static bool AlreadyRun()
        {
            var attr = Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyProductAttribute)) as AssemblyProductAttribute;

            if (attr == null)
            {
                throw new InvalidOperationException("请设置产品名称！");
            }

            if (Mutex.TryOpenExisting(attr.Product, out var mutex))
            {
                return true;
            }

            InstanceMutex = new Mutex(true, attr.Product);

            return false;
        }

        private static void LoadCert(string baseDir)
        {
            // 打开受信任的根证书颁发机构存储  
            using (X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
            {
                // 打开存储区以进行写操作  
                store.Open(OpenFlags.ReadWrite);

                var existingCert = store.Certificates.FirstOrDefault(item => item.Issuer == "O=FlyingEye, L=NONE, S=NONE, C=CH");

                if (existingCert == null)
                {
                    var file = Path.Combine(baseDir, "Assets/certificate.pfx");
                    var cert = new X509Certificate2(file, "1q2w3e*");

                    // 将证书添加到存储区  
                    store.Add(cert);
                }

                // 关闭存储区  
                store.Close();
            }
        }
    }
}
